/*
 * FileName: IssScmConf.java
 * Author:   Administrator
 * Date:     2014-12-2 下午3:38:40
 * Description: //模块目的、功能描述
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.zhangc.zcscm;

import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zhangc.zcscm.client.SCMClientFactory;
import com.zhangc.zcscm.client.SCMListener;
import com.zhangc.zcscm.client.SCMNode;

/**
 * 统一管理SCM的配置
 *
 * @author Administrator
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
public class ScmConfUtil {

    /**
     * 默认实例
     **/
    private static final ScmConfUtil SCM_CONF = new ScmConfUtil();

    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ScmConfUtil.class);

    private SCMNode scmConfNode = null;

    /**
     * conf的配置项
     **/
    private Properties confPro = null;

    /**
     * conf Pro的读写锁
     **/
    private ReadWriteLock confLock = new ReentrantReadWriteLock();

    /**
     * conf Pro 的读锁
     **/
    private Lock confReadLock = confLock.readLock();

    /**
     * conf Pro 的写锁
     **/
    private Lock confWriteLock = confLock.writeLock();

    private ScmConfUtil() {
    }

    /**
     * 返回实例
     *
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public static ScmConfUtil getInstance() {
        return SCM_CONF;
    }

    private void changePro(String s1) {
        // 开始写,需要锁住,获取锁 不能放到try里面
        if (confWriteLock.tryLock()) {
            try {

                confPro = new Properties();

                StringReader read = new StringReader(s1);

                confPro.load(read);

                // 关闭流(由于此流只是单纯把str=null操作 因此不会出异常)
                read.close();
            } catch (IOException e) {

                confPro = null;
                // 打印错误日志
                LOGGER.error("changePro error :{}", s1, e);
            } finally {
                // 释放锁
                confWriteLock.unlock();
            }
        }
    }

    /**
     * 初始化节点信息
     *
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private void init() {

        // 判断是否为空
        if (null == confPro) {

            // 锁住此代码块
            synchronized (SCM_CONF) {

                // 再做一次空判断
                if (null != confPro) {
                    return;
                }
                try {
                    // 判断节点信息是否为空
                    if (null == scmConfNode) {
                        scmConfNode = SCMClientFactory.getSCMClient().getConfig("soof.conf");
                        scmConfNode.sync();
                        scmConfNode.monitor(scmConfNode.getValue(), SCM_CONF.new ScmConfListener());
                    }
                    StringReader read = new StringReader(scmConfNode.getValue());
                    confPro = new Properties();
                    confPro.load(read);
                    // 关闭流(由于此流只是单纯把str=null操作 因此不会出异常)
                    read.close();
                } catch (IOException e) {

                    confPro = null;
                    // 打印错误日志
                    LOGGER.error("init error ", e);
                }
            }
        }
    }

    public int getInt(String key, int defaultValue) {
        String value = this.getString(key, String.valueOf(defaultValue));

        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // 打印错误日志
            LOGGER.error("getInt NumberFormatException ", e);
        }
        return defaultValue;
    }

    public double getDouble(String key, double defaultValue) {
        String value = this.getString(key, String.valueOf(defaultValue));

        try {
            return Double.parseDouble(value);
        } catch (NumberFormatException e) {
            // 打印错误日志
            LOGGER.error("getInt NumberFormatException ", e);
        }
        return defaultValue;
    }

    public boolean getBoolean(String key, boolean defaultValue) {
        String value = this.getString(key, String.valueOf(defaultValue));
        return Boolean.parseBoolean(value);
    }

    /**
     * 通过key=value的方式存储配置项
     *
     * @param key key
     * @return value value
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public String getString(String key, String defaultValue) {
        // 做空判断
        if (StringUtils.isEmpty(key)) {
            return defaultValue;
        }

        // 判断对象是否为空
        // 获取读锁
        if (null != confPro && confReadLock.tryLock()) {
            try {
                // 获取值
                return confPro.getProperty(key, defaultValue);
            } finally {
                // 释放锁
                confReadLock.unlock();
            }
        }

        if (null != confPro) {
            return defaultValue;
        }

        // 如果为空,重新初始化一次
        init();
        // 再判断一次取值
        // 获取读锁
        if (null != confPro && confReadLock.tryLock()) {
            try {
                // 获取值
                return confPro.getProperty(key, defaultValue);
            } finally {
                // 释放锁
                confReadLock.unlock();
            }
        }
        return defaultValue;
    }

    private class ScmConfListener implements SCMListener {
        // 当变化的时候重新初始化pro
        @Override
        public void execute(String oldData, String newData) {
            LOGGER.info("ScmConfUtil.ScmConfListener param, oldData = {}, newData = {}", oldData, newData);
            changePro(newData);
        }
    }
}
